package com.yizisu.playerlibrary.service.download

import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.transformer.ProgressHolder
import com.google.android.exoplayer2.transformer.Transformer
import com.google.android.exoplayer2.util.MimeTypes
import com.yizisu.playerlibrary.PlayerLibInit
import com.yizisu.playerlibrary.impl.exoplayer.buildCacheMediaSourceFactory
import com.yizisu.playerlibrary.impl.exoplayer.buildMediaSourceFactory
import com.yizisu.playerlibrary.impl.exoplayer.mainHandler
import com.yizisu.playerlibrary.view.video_view.helper.logI
import com.yizisu.playerlibrary.view.video_view.helper.playerLibDebug
import java.lang.Exception
import java.util.*


/**
 * 媒体转换类
 * 将在线或者本地文件转为对于的格式
 * outputMimeType 可以参考[MimeTypes]
 */
class PlayerTransformer(
    private val inputMediaItem: MediaItem,
    private val outputPath: String,
    private val formCache: Boolean/*是否是从缓存转换*/,
    private val outputMimeType: OutputType = OutputType.VideoMp4/*只支持MP4和WEBM*/,
    private val overrideExtension: String? = null,
    private val buildBlock: Function1<Transformer.Builder, Unit>? = null
) : Transformer.Listener {
    sealed class OutputType(val mimeType: String) {
        object VideoMp4 : OutputType(MimeTypes.VIDEO_MP4)
        object VideoWebm : OutputType(MimeTypes.VIDEO_WEBM)
    }

    /**
     * 进度监听器
     */
    private var _progressListener: Function3<Int/*进度*/, Boolean/*是否完成*/, Exception?/*异常*/, Unit>? =
        null

    /**
     * transformer
     */
    private val transformer by lazy {
        Transformer.Builder()
            .setContext(PlayerLibInit.app)
            .setOutputMimeType(outputMimeType.mimeType)
            .apply {
                setMediaSourceFactory(
                    if (formCache) {
                        buildCacheMediaSourceFactory(inputMediaItem, overrideExtension)
                    } else {
                        buildMediaSourceFactory(inputMediaItem, null, overrideExtension)
                    }
                )
                buildBlock?.invoke(this)
            }
            //不允许调用者设置监听
            .setListener(this)
            .build()
    }

    private var timer: Timer? = null


    private var timerTask: TimerTask = object : TimerTask() {
        override fun run() {
            mainHandler.post(runTask)
        }
    }

    /**
     * 真正任务的执行逻辑
     */
    private val progressHolder = ProgressHolder()
    private val runTask = Runnable {
        _progressListener?.invoke(currentProgress, false, null)
        if (playerLibDebug) {
            logI("当前转换进度-----> $currentProgress")
        }
    }

    /**
     * 开始任务
     */
    fun start() {
        if (timer != null) {
            return
        }
        try {
            transformer.startTransformation(inputMediaItem, outputPath)
            timer = Timer()
            timer?.schedule(timerTask, 0, 1000/*每秒更新一次*/)
        } catch (e: Exception) {
            if (playerLibDebug) {
                e.printStackTrace()
            }
        }
    }

    fun setTransformerListener(
        listener: Function3<@ParameterName("progress") Int/*进度0-100*/,
                @ParameterName("success") Boolean/*是否完成*/,
                @ParameterName("error") Exception?/*异常*/, Unit>?
    ) {
        _progressListener = listener
    }

    /**
     * 记得关闭任务，否则内存溢出
     */
    fun cancel() {
        transformer.cancel()
        stopTimer()
    }

    /**
     * 停止计时器
     */
    private fun stopTimer() {
        _progressListener = null
        timer?.cancel()
        timer = null
    }

    /**
     * 转换完成
     */
    override fun onTransformationCompleted(inputMediaItem: MediaItem) {
        super.onTransformationCompleted(inputMediaItem)
        _progressListener?.invoke(100, true, null)
        stopTimer()
        if (playerLibDebug) {
            logI("转换成功----->$currentProgress ${inputMediaItem.playbackProperties?.uri}")
        }
    }

    /**
     * 转换失败
     */
    override fun onTransformationError(inputMediaItem: MediaItem, exception: Exception) {
        super.onTransformationError(inputMediaItem, exception)
        _progressListener?.invoke(currentProgress, false, exception)
        stopTimer()
        if (playerLibDebug) {
            logI("转换失败----->$currentProgress ${inputMediaItem.playbackProperties?.uri} \n${exception.message}")
        }
    }

    private val currentProgress: Int
        get() {
            transformer.getProgress(progressHolder)
            return progressHolder.progress
        }
}